{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 配置GPU"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "device  = torch.device('cuda' if torch.cuda.is_available else 'cpu')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 超参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_epochs = 80\n",
    "learning_rate = 0.001"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 图像预处理模组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "transform = transforms.Compose([\n",
    "    transforms.Pad(4),#填充边框\n",
    "    transforms.RandomHorizontalFlip(),#水平翻转\n",
    "    transforms.RandomCrop(32),#切割中心点的位置随机选取\n",
    "    transforms.ToTensor()#PIL.Image转为Torch张量\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## CIFAR-10 数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_dataset = torchvision.datasets.CIFAR10(root='../../data/CIFAR-10',\n",
    "                                            train=True,\n",
    "                                            transform=transform,\n",
    "                                            download=False)\n",
    "test_dataset = torchvision.datasets.CIFAR10(root='../../data/CIFAR-10',\n",
    "                                           train=False,\n",
    "                                           transform=transforms.ToTensor(),\n",
    "                                           download=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据生成器DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loader = torch.utils.data.DataLoader(dataset=train_dataset,\n",
    "                                          batch_size=100,\n",
    "                                          shuffle=True)\n",
    "test_loader = torch.utils.data.DataLoader(dataset=test_dataset,\n",
    "                                         batch_size=100,\n",
    "                                         shuffle=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造 3*3 卷积"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def conv3x3(in_channels, out_channels, stride=1):\n",
    "    return nn.Conv2d(in_channels, out_channels, kernel_size=3,\n",
    "                    stride=stride, padding=1, bias=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造残差模组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResidualBlock(nn.Module):\n",
    "    def __init__(self, in_channels, out_channels, stride=1, downsample=None):\n",
    "        super(ResidualBlock, self).__init__()\n",
    "        self.conv1 = conv3x3(in_channels, out_channels, stride)\n",
    "        self.bn1 = nn.BatchNorm2d(out_channels)\n",
    "        self.relu = nn.ReLU(inplace=True)\n",
    "        self.conv2 = conv3x3(out_channels, out_channels)\n",
    "        self.bn2 = nn.BatchNorm2d(out_channels)\n",
    "        self.downsample = downsample\n",
    "        \n",
    "    def forward(self, x):\n",
    "        residual = x\n",
    "        out = self.conv1(x)\n",
    "        out = self.bn1(out)\n",
    "        out = self.relu(out)\n",
    "        out = self.conv2(out)\n",
    "        out = self.bn2(out)\n",
    "        if self.downsample:\n",
    "            residual = self.downsample(x)#下采样，残差\n",
    "        out += residual\n",
    "        out = self.relu(out)\n",
    "        return out"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造ResNet——残差网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ResNet\n",
    "class ResNet(nn.Module):\n",
    "    def __init__(self, block, layers, num_classes=10):\n",
    "        super(ResNet, self).__init__()\n",
    "        self.in_channels = 16\n",
    "        self.conv = conv3x3(3, 16)\n",
    "        self.bn = nn.BatchNorm2d(16)\n",
    "        self.relu = nn.ReLU(inplace=True)\n",
    "        self.layer1 = self.make_layer(block, 16, layers[0])\n",
    "        self.layer2 = self.make_layer(block, 32, layers[1], 2)\n",
    "        self.layer3 = self.make_layer(block, 64, layers[2], 2)\n",
    "        self.avg_pool = nn.AvgPool2d(8)\n",
    "        self.fc = nn.Linear(64, num_classes)\n",
    "        \n",
    "    def make_layer(self, block, out_channels, blocks, stride=1):\n",
    "        downsample = None\n",
    "        if (stride != 1) or (self.in_channels != out_channels):\n",
    "            downsample = nn.Sequential(\n",
    "                conv3x3(self.in_channels, out_channels, stride=stride),\n",
    "                nn.BatchNorm2d(out_channels))\n",
    "        layers = []\n",
    "        layers.append(block(self.in_channels, out_channels, stride, downsample))\n",
    "        self.in_channels = out_channels\n",
    "        for i in range(1, blocks):\n",
    "            layers.append(block(out_channels, out_channels))\n",
    "        return nn.Sequential(*layers)#*加上形参名的方式来表示这个函数 的实参个数不定，在函数内部都被存放在以形参名为标识符的tuple中。\n",
    "    \n",
    "    \n",
    "    def forward(self, x):\n",
    "        out = self.conv(x)\n",
    "        out = self.bn(out)\n",
    "        out = self.relu(out)\n",
    "        out = self.layer1(out)\n",
    "        out = self.layer2(out)\n",
    "        out = self.layer3(out)\n",
    "        out = self.avg_pool(out)\n",
    "        out = out.view(out.size(0), -1)\n",
    "        out = self.fc(out)\n",
    "        return out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ResNet(ResidualBlock, [2, 2, 2, 2]).to(device)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造 损失 和 优化器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 更新学习率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "def update_lr(optimizer, lr):\n",
    "    for param_group in optimizer.param_groups:\n",
    "        param_group['lr'] = lr#.param_group中保存了参数组及其对应的学习率,动量等等.所以我们可以通过更改param_group[‘lr’]的值来更改对应参数组的学习率"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [1/80], Step [100/500] Loss: 1.5748\n",
      "Epoch [1/80], Step [200/500] Loss: 1.4621\n",
      "Epoch [1/80], Step [300/500] Loss: 1.3846\n",
      "Epoch [1/80], Step [400/500] Loss: 1.2582\n",
      "Epoch [1/80], Step [500/500] Loss: 1.1926\n",
      "Epoch [2/80], Step [100/500] Loss: 0.9526\n",
      "Epoch [2/80], Step [200/500] Loss: 1.1695\n",
      "Epoch [2/80], Step [300/500] Loss: 1.0592\n",
      "Epoch [2/80], Step [400/500] Loss: 1.0909\n",
      "Epoch [2/80], Step [500/500] Loss: 0.9920\n",
      "Epoch [3/80], Step [100/500] Loss: 0.9477\n",
      "Epoch [3/80], Step [200/500] Loss: 1.0780\n",
      "Epoch [3/80], Step [300/500] Loss: 1.0453\n",
      "Epoch [3/80], Step [400/500] Loss: 0.9746\n",
      "Epoch [3/80], Step [500/500] Loss: 0.9332\n",
      "Epoch [4/80], Step [100/500] Loss: 1.0036\n",
      "Epoch [4/80], Step [200/500] Loss: 1.0481\n",
      "Epoch [4/80], Step [300/500] Loss: 0.6685\n",
      "Epoch [4/80], Step [400/500] Loss: 0.6394\n",
      "Epoch [4/80], Step [500/500] Loss: 0.7084\n",
      "Epoch [5/80], Step [100/500] Loss: 0.7055\n",
      "Epoch [5/80], Step [200/500] Loss: 0.6627\n",
      "Epoch [5/80], Step [300/500] Loss: 0.4535\n",
      "Epoch [5/80], Step [400/500] Loss: 0.7463\n",
      "Epoch [5/80], Step [500/500] Loss: 0.6033\n",
      "Epoch [6/80], Step [100/500] Loss: 0.6066\n",
      "Epoch [6/80], Step [200/500] Loss: 0.6568\n",
      "Epoch [6/80], Step [300/500] Loss: 0.5932\n",
      "Epoch [6/80], Step [400/500] Loss: 0.6950\n",
      "Epoch [6/80], Step [500/500] Loss: 0.6215\n",
      "Epoch [7/80], Step [100/500] Loss: 0.7030\n",
      "Epoch [7/80], Step [200/500] Loss: 0.7586\n",
      "Epoch [7/80], Step [300/500] Loss: 0.7199\n",
      "Epoch [7/80], Step [400/500] Loss: 0.6074\n",
      "Epoch [7/80], Step [500/500] Loss: 0.7673\n",
      "Epoch [8/80], Step [100/500] Loss: 0.6718\n",
      "Epoch [8/80], Step [200/500] Loss: 0.5774\n",
      "Epoch [8/80], Step [300/500] Loss: 0.4790\n",
      "Epoch [8/80], Step [400/500] Loss: 0.5426\n",
      "Epoch [8/80], Step [500/500] Loss: 0.4248\n",
      "Epoch [9/80], Step [100/500] Loss: 0.5527\n",
      "Epoch [9/80], Step [200/500] Loss: 0.4739\n",
      "Epoch [9/80], Step [300/500] Loss: 0.5110\n",
      "Epoch [9/80], Step [400/500] Loss: 0.5623\n",
      "Epoch [9/80], Step [500/500] Loss: 0.6152\n",
      "Epoch [10/80], Step [100/500] Loss: 0.6111\n",
      "Epoch [10/80], Step [200/500] Loss: 0.5395\n",
      "Epoch [10/80], Step [300/500] Loss: 0.6926\n",
      "Epoch [10/80], Step [400/500] Loss: 0.7211\n",
      "Epoch [10/80], Step [500/500] Loss: 0.4694\n",
      "Epoch [11/80], Step [100/500] Loss: 0.5937\n",
      "Epoch [11/80], Step [200/500] Loss: 0.3628\n",
      "Epoch [11/80], Step [300/500] Loss: 0.4279\n",
      "Epoch [11/80], Step [400/500] Loss: 0.6256\n",
      "Epoch [11/80], Step [500/500] Loss: 0.6067\n",
      "Epoch [12/80], Step [100/500] Loss: 0.4758\n",
      "Epoch [12/80], Step [200/500] Loss: 0.3477\n",
      "Epoch [12/80], Step [300/500] Loss: 0.3673\n",
      "Epoch [12/80], Step [400/500] Loss: 0.4429\n",
      "Epoch [12/80], Step [500/500] Loss: 0.7263\n",
      "Epoch [13/80], Step [100/500] Loss: 0.3948\n",
      "Epoch [13/80], Step [200/500] Loss: 0.4739\n",
      "Epoch [13/80], Step [300/500] Loss: 0.4799\n",
      "Epoch [13/80], Step [400/500] Loss: 0.4900\n",
      "Epoch [13/80], Step [500/500] Loss: 0.3853\n",
      "Epoch [14/80], Step [100/500] Loss: 0.4927\n",
      "Epoch [14/80], Step [200/500] Loss: 0.3039\n",
      "Epoch [14/80], Step [300/500] Loss: 0.3261\n",
      "Epoch [14/80], Step [400/500] Loss: 0.3521\n",
      "Epoch [14/80], Step [500/500] Loss: 0.4357\n",
      "Epoch [15/80], Step [100/500] Loss: 0.4669\n",
      "Epoch [15/80], Step [200/500] Loss: 0.4356\n",
      "Epoch [15/80], Step [300/500] Loss: 0.3947\n",
      "Epoch [15/80], Step [400/500] Loss: 0.4537\n",
      "Epoch [15/80], Step [500/500] Loss: 0.3776\n",
      "Epoch [16/80], Step [100/500] Loss: 0.4331\n",
      "Epoch [16/80], Step [200/500] Loss: 0.4030\n",
      "Epoch [16/80], Step [300/500] Loss: 0.5447\n",
      "Epoch [16/80], Step [400/500] Loss: 0.3011\n",
      "Epoch [16/80], Step [500/500] Loss: 0.4225\n",
      "Epoch [17/80], Step [100/500] Loss: 0.3056\n",
      "Epoch [17/80], Step [200/500] Loss: 0.2645\n",
      "Epoch [17/80], Step [300/500] Loss: 0.5207\n",
      "Epoch [17/80], Step [400/500] Loss: 0.2575\n",
      "Epoch [17/80], Step [500/500] Loss: 0.3201\n",
      "Epoch [18/80], Step [100/500] Loss: 0.4777\n",
      "Epoch [18/80], Step [200/500] Loss: 0.2958\n",
      "Epoch [18/80], Step [300/500] Loss: 0.4771\n",
      "Epoch [18/80], Step [400/500] Loss: 0.3843\n",
      "Epoch [18/80], Step [500/500] Loss: 0.4879\n",
      "Epoch [19/80], Step [100/500] Loss: 0.3933\n",
      "Epoch [19/80], Step [200/500] Loss: 0.3262\n",
      "Epoch [19/80], Step [300/500] Loss: 0.3840\n",
      "Epoch [19/80], Step [400/500] Loss: 0.4278\n",
      "Epoch [19/80], Step [500/500] Loss: 0.3299\n",
      "Epoch [20/80], Step [100/500] Loss: 0.3608\n",
      "Epoch [20/80], Step [200/500] Loss: 0.4003\n",
      "Epoch [20/80], Step [300/500] Loss: 0.4072\n",
      "Epoch [20/80], Step [400/500] Loss: 0.4971\n",
      "Epoch [20/80], Step [500/500] Loss: 0.5115\n",
      "Epoch [21/80], Step [100/500] Loss: 0.2851\n",
      "Epoch [21/80], Step [200/500] Loss: 0.3389\n",
      "Epoch [21/80], Step [300/500] Loss: 0.2747\n",
      "Epoch [21/80], Step [400/500] Loss: 0.3143\n",
      "Epoch [21/80], Step [500/500] Loss: 0.2758\n",
      "Epoch [22/80], Step [100/500] Loss: 0.3079\n",
      "Epoch [22/80], Step [200/500] Loss: 0.4074\n",
      "Epoch [22/80], Step [300/500] Loss: 0.2609\n",
      "Epoch [22/80], Step [400/500] Loss: 0.2645\n",
      "Epoch [22/80], Step [500/500] Loss: 0.4142\n",
      "Epoch [23/80], Step [100/500] Loss: 0.4451\n",
      "Epoch [23/80], Step [200/500] Loss: 0.1908\n",
      "Epoch [23/80], Step [300/500] Loss: 0.1739\n",
      "Epoch [23/80], Step [400/500] Loss: 0.2640\n",
      "Epoch [23/80], Step [500/500] Loss: 0.2655\n",
      "Epoch [24/80], Step [100/500] Loss: 0.2797\n",
      "Epoch [24/80], Step [200/500] Loss: 0.3592\n",
      "Epoch [24/80], Step [300/500] Loss: 0.2860\n",
      "Epoch [24/80], Step [400/500] Loss: 0.2621\n",
      "Epoch [24/80], Step [500/500] Loss: 0.3126\n",
      "Epoch [25/80], Step [100/500] Loss: 0.4591\n",
      "Epoch [25/80], Step [200/500] Loss: 0.2320\n",
      "Epoch [25/80], Step [300/500] Loss: 0.2849\n",
      "Epoch [25/80], Step [400/500] Loss: 0.2620\n",
      "Epoch [25/80], Step [500/500] Loss: 0.2565\n",
      "Epoch [26/80], Step [100/500] Loss: 0.2614\n",
      "Epoch [26/80], Step [200/500] Loss: 0.1526\n",
      "Epoch [26/80], Step [300/500] Loss: 0.2187\n",
      "Epoch [26/80], Step [400/500] Loss: 0.4135\n",
      "Epoch [26/80], Step [500/500] Loss: 0.2703\n",
      "Epoch [27/80], Step [100/500] Loss: 0.3072\n",
      "Epoch [27/80], Step [200/500] Loss: 0.2277\n",
      "Epoch [27/80], Step [300/500] Loss: 0.3199\n",
      "Epoch [27/80], Step [400/500] Loss: 0.2324\n",
      "Epoch [27/80], Step [500/500] Loss: 0.3315\n",
      "Epoch [28/80], Step [100/500] Loss: 0.3007\n",
      "Epoch [28/80], Step [200/500] Loss: 0.2703\n",
      "Epoch [28/80], Step [300/500] Loss: 0.2690\n",
      "Epoch [28/80], Step [400/500] Loss: 0.2515\n",
      "Epoch [28/80], Step [500/500] Loss: 0.3644\n",
      "Epoch [29/80], Step [100/500] Loss: 0.2471\n",
      "Epoch [29/80], Step [200/500] Loss: 0.1823\n",
      "Epoch [29/80], Step [300/500] Loss: 0.1645\n",
      "Epoch [29/80], Step [400/500] Loss: 0.2718\n",
      "Epoch [29/80], Step [500/500] Loss: 0.2307\n",
      "Epoch [30/80], Step [100/500] Loss: 0.3067\n",
      "Epoch [30/80], Step [200/500] Loss: 0.2533\n",
      "Epoch [30/80], Step [300/500] Loss: 0.1867\n",
      "Epoch [30/80], Step [400/500] Loss: 0.3482\n",
      "Epoch [30/80], Step [500/500] Loss: 0.2488\n",
      "Epoch [31/80], Step [100/500] Loss: 0.2640\n",
      "Epoch [31/80], Step [200/500] Loss: 0.2188\n",
      "Epoch [31/80], Step [300/500] Loss: 0.2006\n",
      "Epoch [31/80], Step [400/500] Loss: 0.3979\n",
      "Epoch [31/80], Step [500/500] Loss: 0.3147\n",
      "Epoch [32/80], Step [100/500] Loss: 0.1492\n",
      "Epoch [32/80], Step [200/500] Loss: 0.3761\n",
      "Epoch [32/80], Step [300/500] Loss: 0.1651\n",
      "Epoch [32/80], Step [400/500] Loss: 0.2603\n",
      "Epoch [32/80], Step [500/500] Loss: 0.1782\n",
      "Epoch [33/80], Step [100/500] Loss: 0.2812\n",
      "Epoch [33/80], Step [200/500] Loss: 0.1128\n",
      "Epoch [33/80], Step [300/500] Loss: 0.2176\n",
      "Epoch [33/80], Step [400/500] Loss: 0.1460\n",
      "Epoch [33/80], Step [500/500] Loss: 0.1949\n",
      "Epoch [34/80], Step [100/500] Loss: 0.2430\n",
      "Epoch [34/80], Step [200/500] Loss: 0.2443\n",
      "Epoch [34/80], Step [300/500] Loss: 0.3191\n",
      "Epoch [34/80], Step [400/500] Loss: 0.1806\n",
      "Epoch [34/80], Step [500/500] Loss: 0.1893\n",
      "Epoch [35/80], Step [100/500] Loss: 0.3966\n",
      "Epoch [35/80], Step [200/500] Loss: 0.4054\n",
      "Epoch [35/80], Step [300/500] Loss: 0.2284\n",
      "Epoch [35/80], Step [400/500] Loss: 0.3222\n",
      "Epoch [35/80], Step [500/500] Loss: 0.3214\n",
      "Epoch [36/80], Step [100/500] Loss: 0.1101\n",
      "Epoch [36/80], Step [200/500] Loss: 0.2873\n",
      "Epoch [36/80], Step [300/500] Loss: 0.2544\n",
      "Epoch [36/80], Step [400/500] Loss: 0.1535\n",
      "Epoch [36/80], Step [500/500] Loss: 0.2215\n",
      "Epoch [37/80], Step [100/500] Loss: 0.2697\n",
      "Epoch [37/80], Step [200/500] Loss: 0.1317\n",
      "Epoch [37/80], Step [300/500] Loss: 0.2503\n",
      "Epoch [37/80], Step [400/500] Loss: 0.3566\n",
      "Epoch [37/80], Step [500/500] Loss: 0.2376\n",
      "Epoch [38/80], Step [100/500] Loss: 0.2829\n",
      "Epoch [38/80], Step [200/500] Loss: 0.2664\n",
      "Epoch [38/80], Step [300/500] Loss: 0.2656\n",
      "Epoch [38/80], Step [400/500] Loss: 0.1627\n",
      "Epoch [38/80], Step [500/500] Loss: 0.2730\n",
      "Epoch [39/80], Step [100/500] Loss: 0.3092\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [39/80], Step [200/500] Loss: 0.2022\n",
      "Epoch [39/80], Step [300/500] Loss: 0.3298\n",
      "Epoch [39/80], Step [400/500] Loss: 0.3501\n",
      "Epoch [39/80], Step [500/500] Loss: 0.2492\n",
      "Epoch [40/80], Step [100/500] Loss: 0.1636\n",
      "Epoch [40/80], Step [200/500] Loss: 0.1156\n",
      "Epoch [40/80], Step [300/500] Loss: 0.2458\n",
      "Epoch [40/80], Step [400/500] Loss: 0.1707\n",
      "Epoch [40/80], Step [500/500] Loss: 0.1913\n",
      "Epoch [41/80], Step [100/500] Loss: 0.2228\n",
      "Epoch [41/80], Step [200/500] Loss: 0.1188\n",
      "Epoch [41/80], Step [300/500] Loss: 0.1215\n",
      "Epoch [41/80], Step [400/500] Loss: 0.2155\n",
      "Epoch [41/80], Step [500/500] Loss: 0.1110\n",
      "Epoch [42/80], Step [100/500] Loss: 0.1514\n",
      "Epoch [42/80], Step [200/500] Loss: 0.1646\n",
      "Epoch [42/80], Step [300/500] Loss: 0.2198\n",
      "Epoch [42/80], Step [400/500] Loss: 0.2520\n",
      "Epoch [42/80], Step [500/500] Loss: 0.1769\n",
      "Epoch [43/80], Step [100/500] Loss: 0.1584\n",
      "Epoch [43/80], Step [200/500] Loss: 0.2582\n",
      "Epoch [43/80], Step [300/500] Loss: 0.1059\n",
      "Epoch [43/80], Step [400/500] Loss: 0.2283\n",
      "Epoch [43/80], Step [500/500] Loss: 0.2672\n",
      "Epoch [44/80], Step [100/500] Loss: 0.0992\n",
      "Epoch [44/80], Step [200/500] Loss: 0.1776\n",
      "Epoch [44/80], Step [300/500] Loss: 0.2270\n",
      "Epoch [44/80], Step [400/500] Loss: 0.1789\n",
      "Epoch [44/80], Step [500/500] Loss: 0.2203\n",
      "Epoch [45/80], Step [100/500] Loss: 0.2845\n",
      "Epoch [45/80], Step [200/500] Loss: 0.2101\n",
      "Epoch [45/80], Step [300/500] Loss: 0.1922\n",
      "Epoch [45/80], Step [400/500] Loss: 0.2185\n",
      "Epoch [45/80], Step [500/500] Loss: 0.3118\n",
      "Epoch [46/80], Step [100/500] Loss: 0.2733\n",
      "Epoch [46/80], Step [200/500] Loss: 0.3566\n",
      "Epoch [46/80], Step [300/500] Loss: 0.2961\n",
      "Epoch [46/80], Step [400/500] Loss: 0.1627\n",
      "Epoch [46/80], Step [500/500] Loss: 0.1546\n",
      "Epoch [47/80], Step [100/500] Loss: 0.1086\n",
      "Epoch [47/80], Step [200/500] Loss: 0.1624\n",
      "Epoch [47/80], Step [300/500] Loss: 0.1820\n",
      "Epoch [47/80], Step [400/500] Loss: 0.1442\n",
      "Epoch [47/80], Step [500/500] Loss: 0.1803\n",
      "Epoch [48/80], Step [100/500] Loss: 0.1589\n",
      "Epoch [48/80], Step [200/500] Loss: 0.2560\n",
      "Epoch [48/80], Step [300/500] Loss: 0.1539\n",
      "Epoch [48/80], Step [400/500] Loss: 0.1398\n",
      "Epoch [48/80], Step [500/500] Loss: 0.1630\n",
      "Epoch [49/80], Step [100/500] Loss: 0.1475\n",
      "Epoch [49/80], Step [200/500] Loss: 0.1953\n",
      "Epoch [49/80], Step [300/500] Loss: 0.1545\n",
      "Epoch [49/80], Step [400/500] Loss: 0.2489\n",
      "Epoch [49/80], Step [500/500] Loss: 0.1823\n",
      "Epoch [50/80], Step [100/500] Loss: 0.2500\n",
      "Epoch [50/80], Step [200/500] Loss: 0.1989\n",
      "Epoch [50/80], Step [300/500] Loss: 0.2688\n",
      "Epoch [50/80], Step [400/500] Loss: 0.1770\n",
      "Epoch [50/80], Step [500/500] Loss: 0.2306\n",
      "Epoch [51/80], Step [100/500] Loss: 0.2223\n",
      "Epoch [51/80], Step [200/500] Loss: 0.1369\n",
      "Epoch [51/80], Step [300/500] Loss: 0.1982\n",
      "Epoch [51/80], Step [400/500] Loss: 0.2191\n",
      "Epoch [51/80], Step [500/500] Loss: 0.2303\n",
      "Epoch [52/80], Step [100/500] Loss: 0.2331\n",
      "Epoch [52/80], Step [200/500] Loss: 0.1451\n",
      "Epoch [52/80], Step [300/500] Loss: 0.2110\n",
      "Epoch [52/80], Step [400/500] Loss: 0.1849\n",
      "Epoch [52/80], Step [500/500] Loss: 0.1883\n",
      "Epoch [53/80], Step [100/500] Loss: 0.2423\n",
      "Epoch [53/80], Step [200/500] Loss: 0.2010\n",
      "Epoch [53/80], Step [300/500] Loss: 0.1444\n",
      "Epoch [53/80], Step [400/500] Loss: 0.1443\n",
      "Epoch [53/80], Step [500/500] Loss: 0.1624\n",
      "Epoch [54/80], Step [100/500] Loss: 0.1185\n",
      "Epoch [54/80], Step [200/500] Loss: 0.2000\n",
      "Epoch [54/80], Step [300/500] Loss: 0.2455\n",
      "Epoch [54/80], Step [400/500] Loss: 0.1049\n",
      "Epoch [54/80], Step [500/500] Loss: 0.2499\n",
      "Epoch [55/80], Step [100/500] Loss: 0.1966\n",
      "Epoch [55/80], Step [200/500] Loss: 0.1161\n",
      "Epoch [55/80], Step [300/500] Loss: 0.2901\n",
      "Epoch [55/80], Step [400/500] Loss: 0.0938\n",
      "Epoch [55/80], Step [500/500] Loss: 0.1527\n",
      "Epoch [56/80], Step [100/500] Loss: 0.1859\n",
      "Epoch [56/80], Step [200/500] Loss: 0.1619\n",
      "Epoch [56/80], Step [300/500] Loss: 0.1487\n",
      "Epoch [56/80], Step [400/500] Loss: 0.1135\n",
      "Epoch [56/80], Step [500/500] Loss: 0.1921\n",
      "Epoch [57/80], Step [100/500] Loss: 0.3338\n",
      "Epoch [57/80], Step [200/500] Loss: 0.2211\n",
      "Epoch [57/80], Step [300/500] Loss: 0.1666\n",
      "Epoch [57/80], Step [400/500] Loss: 0.1875\n",
      "Epoch [57/80], Step [500/500] Loss: 0.1686\n",
      "Epoch [58/80], Step [100/500] Loss: 0.3327\n",
      "Epoch [58/80], Step [200/500] Loss: 0.1331\n",
      "Epoch [58/80], Step [300/500] Loss: 0.1847\n",
      "Epoch [58/80], Step [400/500] Loss: 0.1636\n",
      "Epoch [58/80], Step [500/500] Loss: 0.1319\n",
      "Epoch [59/80], Step [100/500] Loss: 0.2951\n",
      "Epoch [59/80], Step [200/500] Loss: 0.0982\n",
      "Epoch [59/80], Step [300/500] Loss: 0.1608\n",
      "Epoch [59/80], Step [400/500] Loss: 0.1788\n",
      "Epoch [59/80], Step [500/500] Loss: 0.1764\n",
      "Epoch [60/80], Step [100/500] Loss: 0.2494\n",
      "Epoch [60/80], Step [200/500] Loss: 0.2849\n",
      "Epoch [60/80], Step [300/500] Loss: 0.1330\n",
      "Epoch [60/80], Step [400/500] Loss: 0.1180\n",
      "Epoch [60/80], Step [500/500] Loss: 0.1853\n",
      "Epoch [61/80], Step [100/500] Loss: 0.1750\n",
      "Epoch [61/80], Step [200/500] Loss: 0.1935\n",
      "Epoch [61/80], Step [300/500] Loss: 0.0920\n",
      "Epoch [61/80], Step [400/500] Loss: 0.2292\n",
      "Epoch [61/80], Step [500/500] Loss: 0.1087\n",
      "Epoch [62/80], Step [100/500] Loss: 0.1231\n",
      "Epoch [62/80], Step [200/500] Loss: 0.1388\n",
      "Epoch [62/80], Step [300/500] Loss: 0.1314\n",
      "Epoch [62/80], Step [400/500] Loss: 0.1806\n",
      "Epoch [62/80], Step [500/500] Loss: 0.1280\n",
      "Epoch [63/80], Step [100/500] Loss: 0.1338\n",
      "Epoch [63/80], Step [200/500] Loss: 0.2216\n",
      "Epoch [63/80], Step [300/500] Loss: 0.1251\n",
      "Epoch [63/80], Step [400/500] Loss: 0.1596\n",
      "Epoch [63/80], Step [500/500] Loss: 0.1396\n",
      "Epoch [64/80], Step [100/500] Loss: 0.1029\n",
      "Epoch [64/80], Step [200/500] Loss: 0.2163\n",
      "Epoch [64/80], Step [300/500] Loss: 0.1151\n",
      "Epoch [64/80], Step [400/500] Loss: 0.1855\n",
      "Epoch [64/80], Step [500/500] Loss: 0.1636\n",
      "Epoch [65/80], Step [100/500] Loss: 0.2177\n",
      "Epoch [65/80], Step [200/500] Loss: 0.1668\n",
      "Epoch [65/80], Step [300/500] Loss: 0.1298\n",
      "Epoch [65/80], Step [400/500] Loss: 0.1563\n",
      "Epoch [65/80], Step [500/500] Loss: 0.2088\n",
      "Epoch [66/80], Step [100/500] Loss: 0.1654\n",
      "Epoch [66/80], Step [200/500] Loss: 0.1567\n",
      "Epoch [66/80], Step [300/500] Loss: 0.1859\n",
      "Epoch [66/80], Step [400/500] Loss: 0.2715\n",
      "Epoch [66/80], Step [500/500] Loss: 0.1828\n",
      "Epoch [67/80], Step [100/500] Loss: 0.2242\n",
      "Epoch [67/80], Step [200/500] Loss: 0.2767\n",
      "Epoch [67/80], Step [300/500] Loss: 0.1076\n",
      "Epoch [67/80], Step [400/500] Loss: 0.1291\n",
      "Epoch [67/80], Step [500/500] Loss: 0.2093\n",
      "Epoch [68/80], Step [100/500] Loss: 0.1416\n",
      "Epoch [68/80], Step [200/500] Loss: 0.1408\n",
      "Epoch [68/80], Step [300/500] Loss: 0.0906\n",
      "Epoch [68/80], Step [400/500] Loss: 0.0947\n",
      "Epoch [68/80], Step [500/500] Loss: 0.1020\n",
      "Epoch [69/80], Step [100/500] Loss: 0.1188\n",
      "Epoch [69/80], Step [200/500] Loss: 0.1699\n",
      "Epoch [69/80], Step [300/500] Loss: 0.0887\n",
      "Epoch [69/80], Step [400/500] Loss: 0.2083\n",
      "Epoch [69/80], Step [500/500] Loss: 0.2831\n",
      "Epoch [70/80], Step [100/500] Loss: 0.1550\n",
      "Epoch [70/80], Step [200/500] Loss: 0.1599\n",
      "Epoch [70/80], Step [300/500] Loss: 0.1472\n",
      "Epoch [70/80], Step [400/500] Loss: 0.2507\n",
      "Epoch [70/80], Step [500/500] Loss: 0.1875\n",
      "Epoch [71/80], Step [100/500] Loss: 0.1507\n",
      "Epoch [71/80], Step [200/500] Loss: 0.1265\n",
      "Epoch [71/80], Step [300/500] Loss: 0.1672\n",
      "Epoch [71/80], Step [400/500] Loss: 0.0647\n",
      "Epoch [71/80], Step [500/500] Loss: 0.2730\n",
      "Epoch [72/80], Step [100/500] Loss: 0.0891\n",
      "Epoch [72/80], Step [200/500] Loss: 0.2088\n",
      "Epoch [72/80], Step [300/500] Loss: 0.1581\n",
      "Epoch [72/80], Step [400/500] Loss: 0.0962\n",
      "Epoch [72/80], Step [500/500] Loss: 0.1145\n",
      "Epoch [73/80], Step [100/500] Loss: 0.1279\n",
      "Epoch [73/80], Step [200/500] Loss: 0.0760\n",
      "Epoch [73/80], Step [300/500] Loss: 0.1956\n",
      "Epoch [73/80], Step [400/500] Loss: 0.2002\n",
      "Epoch [73/80], Step [500/500] Loss: 0.1724\n",
      "Epoch [74/80], Step [100/500] Loss: 0.1242\n",
      "Epoch [74/80], Step [200/500] Loss: 0.1487\n",
      "Epoch [74/80], Step [300/500] Loss: 0.2371\n",
      "Epoch [74/80], Step [400/500] Loss: 0.1978\n",
      "Epoch [74/80], Step [500/500] Loss: 0.2154\n",
      "Epoch [75/80], Step [100/500] Loss: 0.1541\n",
      "Epoch [75/80], Step [200/500] Loss: 0.1695\n",
      "Epoch [75/80], Step [300/500] Loss: 0.2130\n",
      "Epoch [75/80], Step [400/500] Loss: 0.1240\n",
      "Epoch [75/80], Step [500/500] Loss: 0.1861\n",
      "Epoch [76/80], Step [100/500] Loss: 0.1270\n",
      "Epoch [76/80], Step [200/500] Loss: 0.2889\n",
      "Epoch [76/80], Step [300/500] Loss: 0.1727\n",
      "Epoch [76/80], Step [400/500] Loss: 0.2446\n",
      "Epoch [76/80], Step [500/500] Loss: 0.1040\n",
      "Epoch [77/80], Step [100/500] Loss: 0.0934\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [77/80], Step [200/500] Loss: 0.2776\n",
      "Epoch [77/80], Step [300/500] Loss: 0.1860\n",
      "Epoch [77/80], Step [400/500] Loss: 0.2562\n",
      "Epoch [77/80], Step [500/500] Loss: 0.2118\n",
      "Epoch [78/80], Step [100/500] Loss: 0.1411\n",
      "Epoch [78/80], Step [200/500] Loss: 0.1329\n",
      "Epoch [78/80], Step [300/500] Loss: 0.1104\n",
      "Epoch [78/80], Step [400/500] Loss: 0.1810\n",
      "Epoch [78/80], Step [500/500] Loss: 0.3269\n",
      "Epoch [79/80], Step [100/500] Loss: 0.1829\n",
      "Epoch [79/80], Step [200/500] Loss: 0.0803\n",
      "Epoch [79/80], Step [300/500] Loss: 0.1459\n",
      "Epoch [79/80], Step [400/500] Loss: 0.0816\n",
      "Epoch [79/80], Step [500/500] Loss: 0.1490\n",
      "Epoch [80/80], Step [100/500] Loss: 0.1704\n",
      "Epoch [80/80], Step [200/500] Loss: 0.1283\n",
      "Epoch [80/80], Step [300/500] Loss: 0.0978\n",
      "Epoch [80/80], Step [400/500] Loss: 0.1558\n",
      "Epoch [80/80], Step [500/500] Loss: 0.1820\n"
     ]
    }
   ],
   "source": [
    "total_step = len(train_loader)\n",
    "curr_lr = learning_rate\n",
    "for epoch in range(num_epochs):\n",
    "    for i, (images, labels) in enumerate(train_loader):\n",
    "        images = images.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向传播\n",
    "        outputs = model(images)\n",
    "        loss = criterion(outputs, labels)\n",
    "        # 反向传播 和 优化\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        if (i+1) % 100 == 0:\n",
    "            print (\"Epoch [{}/{}], Step [{}/{}] Loss: {:.4f}\"\n",
    "                   .format(epoch+1, num_epochs, i+1, total_step, loss.item()))\n",
    "\n",
    "    # 学习率衰减\n",
    "    if (epoch+1) % 20 == 0:\n",
    "        curr_lr /= 3\n",
    "        update_lr(optimizer, curr_lr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 保存模型检查点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.save(model.state_dict(), 'resnet.ckpt')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "tensorflow-gpu",
   "language": "python",
   "name": "tensorflow-gpu"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
